<?php

namespace App\Library\Service;

use App\Library\Logic\AfterSaleLogic;
use App\Library\Logic\AuctionBailLogic;
use App\Library\Logic\AuctionLogic;
use App\Library\Logic\AuctionOrderLogic;
use App\Library\Logic\NotifyLogic;
use App\Library\Logic\PaymentLogic;
use App\Library\Logic\RefundLogic;
use App\Library\Logic\ShopOrderLogic;
use App\Library\Logic\ShopOrderReturnLogic;
use App\Library\Logic\ZbBailLogic;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Psr\Http\Message\ResponseInterface;
use Yansongda\Artful\Exception\ContainerException;
use Yansongda\Artful\Exception\InvalidParamsException;
use Yansongda\Artful\Exception\ServiceNotFoundException;
use Yansongda\Artful\Rocket;
use Yansongda\Pay\Pay;
use Yansongda\Supports\Collection;

class WechatService extends BaseService
{
    /**
     * 保证金退款回调
     * @return JsonResponse
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function auctionBailRefund(): JsonResponse
    {file_put_contents('./auctionBailRefund.txt','auctionBailRefund');
        $result = Pay::wechat()->callback(request()->post());
        $this->hWechatRefund($result);
        $outRefundNo = $result->get('resource.ciphertext.out_refund_no');
        if (is_null($outRefundNo)) return success();
        $order = AuctionBailLogic::findBySerialNumber($outRefundNo);
        if (is_null($order)) return fail();
        else if ($order->status !== 2) return fail();
        else if ($order->status_pay !== 1) return fail();
        else if (is_null($order->pay_at)) return fail();
        else if ($order->status_bail !== 99) return fail();
        else if (is_null($order->paymentRelated)) return fail();
        else if (is_null($order->payment)) return fail();
        $auction = AuctionLogic::detail($order->auction_id);
        if (is_null($auction)) return fail();
        else if ($auction->sell_out === 0 && $auction->expired === 0) return fail();
        $order->status_bail = $auction->expired === 1 ? 1 : 2;
        if (AuctionOrderLogic::query()->where(humpToLine([
            'auctionId' => $order->auction_id,
            'userId' => $order->user_id,
            'statusPay' => 1,
        ]))->whereNotNull('pay_at')->count()) $order->status_bail = 3;
        $order->refund_price = $order->order_price;
        $order->refund_at = $result->get('resource.ciphertext.success_time');
        $order->save();
        $order->paymentRelated->status_refund = 1;
        $order->paymentRelated->save();
        return success();
    }

    /**
     * 售后退款回调
     * @return JsonResponse
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function afterSaleRefund(): JsonResponse
    {file_put_contents('./afterSaleRefund.txt','afterSaleRefund');
        $result = Pay::wechat()->callback(request()->post());
        $this->hWechatRefund($result);
        $outRefundNo = $result->get('resource.ciphertext.out_refund_no');
        if (is_null($outRefundNo)) return fail();
        $afterSale = AfterSaleLogic::findBySerialNumber($outRefundNo);
        if (is_null($afterSale)) return fail();
        else if ($afterSale->status_arrival !== 99) return fail();
        else if (is_null($afterSale->agree_at)) return fail();
        $afterSale->arrival_at = $result->get('resource.ciphertext.success_time');
        $afterSale->status_arrival = 1;
        $afterSale->save();
        $afterSale->paymentRelated->status_refund = 1;
        $afterSale->paymentRelated->save();
        if ($afterSale->object_type === 'auction_order') {
            $afterSale->auctionOrder->refund_price = $afterSale->refund_price;
            $afterSale->auctionOrder->status_refund = 1;
            $afterSale->auctionOrder->refund_at = $afterSale->arrival_at;
            $afterSale->auctionOrder->save();
        }
        return success();
    }

    /**
     * 保证金退款回调
     * @return JsonResponse
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function zbBailRefund(): JsonResponse
    {file_put_contents('./zbBailRefund.txt','zbBailRefund');
        $result = Pay::wechat()->callback(request()->post());
        $this->hWechatRefund($result);
        $outRefundNo = $result->get('resource.ciphertext.out_refund_no');
        if (is_null($outRefundNo)) return fail();
        $zbBail = ZbBailLogic::findBySerialNumber($outRefundNo);
        if (is_null($zbBail)) return fail();
        else if ($zbBail->status_refund !== 99) return fail();
        else if (!is_null($zbBail->refund_at)) return fail();
        else if (is_null($zbBail->payment)) return fail();
        else if (is_null($zbBail->paymentRelated)) return fail();
        $zbBail->status_refund = 1;
        $zbBail->refund_price = $zbBail->pay_price;;
        $zbBail->refund_at = $result->get('resource.ciphertext.success_time');
        $zbBail->save();
        $zbBail->paymentRelated->status_refund = 1;
        $zbBail->paymentRelated->save();
        return success();
    }

    /**
     * notify
     * @return ResponseInterface
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     * @throws Exception
     */
    public function notify(): ResponseInterface
    {file_put_contents('./notify.txt','notify');
        $result = Pay::wechat()->callback(request()->post());
        NotifyLogic::insertForModel('result', $result);
        if (in_array($result->get('resource.ciphertext.attach'), ['auction_order', 'auction_bail', 'zb_bail'])) {
            Log::critical(random(), $result->toArray());
            return PayService::wechatNotify($result);
        } else if ($result->get('resource.ciphertext.attach') === 'shop_order') {
            return PayService::notify();
        } else if ($result->get('resource.ciphertext.attach') === 'payOrder') {//单商品支付回调
            if ($result->get('resource.ciphertext.trade_state') !== 'SUCCESS') return Pay::wechat()->success();
            $shopOrder = ShopOrderLogic::findByWhere('order_sn', $result->get('resource.ciphertext.out_trade_no'));
            if (is_null($shopOrder)) return Pay::wechat()->success();
            $shopOrder->order_status = 1;
            $shopOrder->order_buy_status = 1;
            $shopOrder->order_sell_status = 1;
            $shopOrder->order_pay_order_sn = $result->get('resource.ciphertext.transaction_id');
            $shopOrder->order_pay_callback_json = json_encode($result);
            $shopOrder->order_pay_api_status = 'SUCCESS';
            $shopOrder->order_pay_time = strtotime($result->get('resource.ciphertext.success_time'));
            $shopOrder->save();
            mq('productOrderNotify', $shopOrder->serial_number);
        }
        return Pay::wechat()->success();
    }

    /**
     * notifyRefund
     * @return ResponseInterface
     * @throws Exception
     */
    public function notifyRefund(): ResponseInterface
    {file_put_contents('./notifyRefund.txt','notifyRefund');
        $result = Pay::wechat()->callback(request()->post());
        $this->hWechatRefund($result);
        $outRefundNo = $result->get('resource.ciphertext.out_refund_no');
        if (is_null($outRefundNo)) return Pay::wechat()->success();
        else if ($result->get('resource.ciphertext.refund_status') !== 'SUCCESS') return Pay::wechat()->success();
        $shopOrderReturn = ShopOrderReturnLogic::findByWhere('or_sn', $outRefundNo);
        if (is_null($shopOrderReturn)) {
            $shopOrderReturn = ShopOrderReturnLogic::findBySerialNumber($outRefundNo);
            if (is_null($shopOrderReturn)) return Pay::wechat()->success();
        }
        $shopOrderReturn->or_buy_status = 6;
        $shopOrderReturn->or_sell_status = 6;
        $shopOrderReturn->or_api_order_sn = $result->get('resource.ciphertext.refund_id');
        $shopOrderReturn->or_api_status = 'SUCCESS';
        $shopOrderReturn->or_api_callback_json = json_encode($result);
        $shopOrderReturn->or_api_time = strtotime($result->get('resource.ciphertext.success_time'));
        $shopOrderReturn->save();
        mq('shopOrderReturn', $shopOrderReturn);
        return Pay::wechat()->success();
    }


    /**
     * hWechatRefund
     * @throws ServiceNotFoundException
     * @throws InvalidParamsException
     * @throws ContainerException
     */
    private function hWechatRefund(Collection|Rocket $result): void
    {
        NotifyLogic::insertForModel(['type' => 1, 'result' => $result]);
        $transactionId = $result->get('resource.ciphertext.transaction_id');
        $list = PaymentLogic::getByWhere('outTradeNo', $transactionId, 'id');
        if ($list->count() === 0) return;
        $refundId = $result->get('resource.ciphertext.refund_id');
        $outRefundNo = $result->get('resource.ciphertext.out_refund_no');
        $amount = $result->get('resource.ciphertext.amount.payer_refund');
        foreach ($list as $v) {
            if (RefundLogic::existsByWhere('refundId', $refundId)) return;
            $refund = RefundLogic::insertForModel([
                'outRefundNo' => $outRefundNo,
                'refundId' => $refundId,
                'paymentId' => $v->id,
                'amount' => bcdiv($amount, 100, 2),
                'result' => Pay::wechat()->query(['out_refund_no' => $outRefundNo, '_action' => 'refund']),
            ]);
            PaymentLogic::updateById($v->id, ['statusRefund' => 1, 'refund' => $refund->result]);
        }
    }
}
